package wsp.dailymarket.admin;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.annotation.Resource;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.ArrayDataModel;
import javax.faces.model.DataModel;
import javax.sql.DataSource;
import wsp.dailymarket.auth.AuthenticationBean;
import wsp.dailymarket.obj.UserProfileBean;

/**
 * Backing bean to the Manage Users Admin view
 * @author Matt
 */
@ManagedBean(name = "userListBean")
@SessionScoped
public class ClientListBean {

	@Resource(name = "jdbc/dmderby")
	private DataSource ds;

	@ManagedProperty(value = "#{authenticationBean}")
	private AuthenticationBean authBean;

	private DataModel<EditableClient> clientListModel;
	private ArrayList<EditableClient> clientList;
	private boolean existingClient;
	private EditableClient client;

	public ClientListBean() {
		clientList = new ArrayList<EditableClient>();
	}

	public String doAdvancedEditClient(EditableClient client) {
		this.client = client;
		existingClient = true;
		return "client_editor";
	}

	public String doCreateNewClient() {
		client = new EditableClient();
		existingClient = false;
		return "client_editor";
	}

	public String doSaveClient() {
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				String sql = null;
				if (this.existingClient) {
					sql = "UPDATE APP.CLIENTS SET "
							+ "password = '"
							+ this.client.getPassword()
							+ "', "
							+ "firstname = '"
							+ this.client.getUserProfile().getFirstName()
							+ "', "
							+ "lastname = '"
							+ this.client.getUserProfile().getLastName()
							+ "', "
							+ "companyname = '"
							+ this.client.getUserProfile().getCompanyName()
							+ "', "
							+ "address_line1 = '"
							+ this.client.getUserProfile().getAddressLine1()
							+ "', "
							+ "address_line2 = '"
							+ this.client.getUserProfile().getAddressLine2()
							+ "', "
							+ "address_city = '"
							+ this.client.getUserProfile().getAddressCity()
							+ "', "
							+ "address_state = '"
							+ this.client.getUserProfile().getAddressState()
							+ "', "
							+ "address_zipcode = '"
							+ this.client.getUserProfile().getAddressZipCode()
							+ "' "
							+ "WHERE client_id = '"
							+ this.client.getClientID()
							+ "'";
				} else {
					sql = "INSERT INTO APP.CLIENTS (client_id, password, firstname, lastname, companyname, address_line1, address_line2, address_city, address_state, address_zipcode, client_type)"
							+ " VALUES ('"
							+ this.client.getClientID()
							+ "', '"
							+ this.client.getPassword()
							+ "', '"
							+ this.client.getUserProfile().getFirstName()
							+ "', '"
							+ this.client.getUserProfile().getLastName()
							+ "', '"
							+ this.client.getUserProfile().getCompanyName()
							+ "', '"
							+ this.client.getUserProfile().getAddressLine1()
							+ "', '"
							+ this.client.getUserProfile().getAddressLine2()
							+ "', '"
							+ this.client.getUserProfile().getAddressCity()
							+ "', '"
							+ this.client.getUserProfile().getAddressState()
							+ "', '"
							+ this.client.getUserProfile().getAddressZipCode()
							+ "', "
							+ this.client.getClientType()
							+ ")";
				}
				if (stmt.executeUpdate(sql) == 1) {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_INFO);
					msg.setSummary(this.existingClient ? "Client Profile Saved" : "New Client Saved");
					FacesContext.getCurrentInstance().addMessage(null, msg);
					this.loadClients();
					return "manage_clients";
				} else {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_ERROR);
					msg.setSummary("Could not save to database!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
					return null;
				}
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary("Database Error");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return null;
		}

	}

	/**
	 * Begin a simple client edit
	 * @param user Client to edit
	 * @return Outcome to same place (null)
	 */
	public String doEditClient(EditableClient user) {
		// Cancel edits for all other clients
		this.doCancelEditClient();

		// Make this client editable
		clientList.get(clientList.indexOf(user)).setEditable(true);

		// Make it THE client
		this.client = user;

		// Stay on the same view
		return null;
	}

	/**
	 * Commit the simple changes to database
	 * @param user Client to commit
	 * @return Outcome to same place (null)
	 */
	public String doCommitEditClient(EditableClient user) {
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				String sql = "UPDATE APP.CLIENTS SET password='"
						+ user.getPassword()
						+ "', client_type="
						+ user.getClientType()
						+ " WHERE client_id = '"
						+ user.getClientID()
						+ "'";
				if (stmt.executeUpdate(sql) == 1) {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_INFO);
					msg.setSummary("Saved changes to \"" + user.getClientID() + "\"!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				} else {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_ERROR);
					msg.setSummary("Error saving changes!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				}
				this.loadClients();
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary("Database Error");
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}
		return this.doCancelEditClient();
	}

	/**
	 * Cancel edits for all clients
	 * @return Outcome to same place (null)
	 */
	public String doCancelEditClient() {
		for (int i = 0; i < clientList.size(); i++) {
			clientList.get(i).setEditable(false);
		}
		return null;
	}

	/**
	 * Delete a client from the database
	 * @param user Client to delete
	 * @return Outcome to same place (null)
	 */
	public String doDeleteClient(EditableClient thisClient) {
		if (thisClient.getClientID().equals(authBean.getUserProfile().getEmailAddress())) {
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_ERROR);
			msg.setSummary("You cannot delete yourself!");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return null;
		}
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				String sql = "DELETE FROM APP.CLIENTS WHERE client_id = '"
						+ thisClient.getClientID()
						+ "'";
				if (stmt.executeUpdate(sql) == 1) {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_INFO);
					msg.setSummary("Successfully deleted \"" + thisClient.getClientID() + "\"!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				} else {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_ERROR);
					msg.setSummary("Delete client failed!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				}
				this.loadClients();
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary("Database Error");
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}
		return null;
	}

	/**
	 * Call this method to reload the user table (also resets all editable flags to false)
	 */
	public void loadClients() {
		clientList = new ArrayList<EditableClient>();
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				ResultSet rs = stmt.executeQuery("SELECT * FROM APP.CLIENTS");

				while (rs.next()) {
					UserProfileBean newUP = new UserProfileBean(
							rs.getString("CLIENT_ID"),
							rs.getString("FIRSTNAME"),
							rs.getString("LASTNAME"),
							rs.getString("COMPANYNAME"),
							rs.getString("ADDRESS_LINE1"),
							rs.getString("ADDRESS_LINE2"),
							rs.getString("ADDRESS_CITY"),
							rs.getString("ADDRESS_STATE"),
							rs.getString("ADDRESS_ZIPCODE"),
							rs.getInt("CLIENT_TYPE"));
					EditableClient newEU = new EditableClient();
					newEU.setPassword(rs.getString("PASSWORD"));
					newEU.setClientID(rs.getString("CLIENT_ID"));
					newEU.setClientTypeInt(rs.getInt("CLIENT_TYPE"));
					newEU.setUserProfile(newUP);
					clientList.add(newEU);
				}
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary("Database Error");
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}
		this.clientListModel = new ArrayDataModel<EditableClient>();
		this.clientListModel.setWrappedData(clientList.toArray());
	}

	/**
	 * Magic method that loads users only if it needs to
	 * @return If there are actually any users in the list after we load them
	 */
	public boolean getClients() {
		if (!this.getClientsExist()) {
			loadClients();
		}
		return this.getClientsExist();
	}

	public EditableClient getEditableUser() {
		return this.client;
	}

	public DataModel<EditableClient> getClientList() {
		return this.clientListModel;
	}

	public boolean getClientsExist() {
		return !this.clientList.isEmpty();
	}

	public boolean isExistingClient() {
		return this.existingClient;
	}

	public void setAuthBean(AuthenticationBean newValue) {
		this.authBean = newValue;
	}
}
